package server

import (
	"fmt"
	"net"
	"sync"
	"time"

	pb "go-war3proxy/pkg/proto"
	"go-war3proxy/pkg/utils"

	"go.uber.org/zap"
)

// ClientSession 客户端会话对象，负责处理自身的消息和广播
type ClientSession struct {
	war3IP string
	conn   net.Conn
	queue  chan net.Conn
	logger *zap.Logger
	mutex  sync.RWMutex
}

// NewClientSession 创建新的客户端会话
func NewClientSession(war3IP string, conn net.Conn, logger *zap.Logger) *ClientSession {
	return &ClientSession{
		war3IP: war3IP,
		conn:   conn,
		queue:  make(chan net.Conn, 10),
		logger: logger.With(zap.String("war3IP", war3IP)),
	}
}

// GetWar3IP 获取War3 IP地址
func (cs *ClientSession) GetWar3IP() string {
	return cs.war3IP
}

// PutToQueue 将连接放入队列
func (cs *ClientSession) PutToQueue(conn net.Conn) {
	select {
	case cs.queue <- conn:
		cs.logger.Info("连接已放入队列")
	default:
		cs.logger.Warn("队列已满，关闭连接")
		conn.Close()
	}
}

// PollQueue 从队列中取出连接 (带超时)
func (cs *ClientSession) PollQueue() net.Conn {
	select {
	case conn := <-cs.queue:
		return conn
	case <-time.After(3 * time.Second):
		return nil
	}
}

// Notification 通知客户端有新事件
func (cs *ClientSession) Notification() error {
	cs.mutex.RLock()
	defer cs.mutex.RUnlock()

	if cs.conn == nil {
		return fmt.Errorf("连接为空，无法发送数据")
	}

	if !cs.isConnected() {
		return fmt.Errorf("连接已关闭，无法发送数据")
	}

	notification := &pb.Notification{}
	message := &pb.War3Message{
		Type:    pb.MessageType_NOTIFICATION,
		Payload: &pb.War3Message_Notification{Notification: notification},
	}

	return utils.SendProtobufMessage(cs.conn, message, cs.logger)
}

// UpdateClientList 更新客户端列表，有新的客户端加入
func (cs *ClientSession) UpdateClientList(clientMap map[string]*ClientSession) {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()

	if cs.conn == nil || !cs.isConnected() {
		cs.logger.Error("连接无效，无法更新客户端列表")
		return
	}

	// 构建其他客户端IP列表
	var otherIPs []string
	for ip := range clientMap {
		if ip != cs.war3IP {
			otherIPs = append(otherIPs, ip)
		}
	}

	if len(otherIPs) > 0 {
		clientListUpdate := &pb.ClientListUpdate{
			ClientIps: otherIPs,
		}

		message := &pb.War3Message{
			Type:    pb.MessageType_CLIENT_LIST_UPDATE,
			Payload: &pb.War3Message_ClientListUpdate{ClientListUpdate: clientListUpdate},
		}

		cs.logger.Info("更新客户端列表", zap.Strings("ips", otherIPs))
		if err := utils.SendProtobufMessage(cs.conn, message, cs.logger); err != nil {
			cs.logger.Error("发送客户端列表更新失败", zap.Error(err))
		}
	}
}

// Start 启动客户端会话处理
func (cs *ClientSession) Start(server *Server) {
	defer func() {
		cs.conn.Close()
		server.RemoveClient(cs.war3IP)
		server.ipPool.ReleaseIP(cs.war3IP)
		cs.logger.Info("客户端会话结束")
	}()

	for {
		message, err := utils.ReceiveProtobufMessage(cs.conn, cs.logger)
		if err != nil {
			cs.logger.Error("接收消息失败", zap.Error(err))
			break
		}

		if err := cs.handleMessage(message, server); err != nil {
			cs.logger.Error("处理消息失败", zap.Error(err))
			break
		}
	}
}

// handleMessage 处理客户端消息
func (cs *ClientSession) handleMessage(message *pb.War3Message, server *Server) error {
	switch message.Type {
	case pb.MessageType_DATA_FORWARD:
		return cs.handleDataForward(message, server)
	default:
		return fmt.Errorf("不支持的消息类型: %s", message.Type.String())
	}
}

// handleDataForward 处理数据转发消息
func (cs *ClientSession) handleDataForward(message *pb.War3Message, server *Server) error {
	dataForward := message.GetPayload().(*pb.War3Message_DataForward).DataForward
	otherWar3IP := dataForward.FromIp
	targetIP := message.TargetIp

	cs.logger.Info("转发数据",
		zap.String("from_ip", cs.war3IP),
		zap.String("to_ip", otherWar3IP),
		zap.String("target_ip", targetIP),
		zap.Int("data_size", len(dataForward.Data)))

	// 转发给fromIp对应的客户端
	clientSession := server.GetClient(otherWar3IP)
	if clientSession == nil {
		return fmt.Errorf("未找到目标客户端: %s", otherWar3IP)
	}

	clientSession.mutex.RLock()
	conn := clientSession.conn
	clientSession.mutex.RUnlock()

	if conn == nil || !clientSession.isConnected() {
		return fmt.Errorf("目标客户端连接无效: %s", otherWar3IP)
	}

	forwardMessage := &pb.War3Message{
		Type:     pb.MessageType_DATA_FORWARD,
		SourceIp: otherWar3IP,
		TargetIp: targetIP,
		Payload:  &pb.War3Message_DataForward{DataForward: dataForward},
	}

	return utils.SendProtobufMessage(conn, forwardMessage, cs.logger)
}

// isConnected 检查连接是否有效
func (cs *ClientSession) isConnected() bool {
	if cs.conn == nil {
		return false
	}

	// 检查连接是否已关闭
	return cs.conn.LocalAddr() != nil && cs.conn.RemoteAddr() != nil
}
